﻿using System;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Data.Services.Client;
using FindMyChamp.ChampDataService;
using System.Collections.ObjectModel;
using System.Device.Location;

namespace FindMyChamp
{
    public class ViewModel : INotifyPropertyChanged
    {
        public static bool IsDataLoaded = false;
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler DistanceChanged;

        public ViewModel()
        {
            GeoData.PositionChanged += (s, e) =>
            {
                CurrentLocation = GeoData.Location;
            };
        }

        #region Props

        // the map data binds to this
        private GeoCoordinate m_CurrentLocation;
        public GeoCoordinate CurrentLocation
        {
            get { return m_CurrentLocation; }
            set
            {
                m_CurrentLocation = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("CurrentLocation"));
            }
        }

        // the progress bar data binds to this
        private Visibility m_ProgressBarVisibility = Visibility.Collapsed;
        public Visibility ProgressBarVisibility
        {
            get { return m_ProgressBarVisibility; }
            set
            {
                m_ProgressBarVisibility = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("ProgressBarVisibility"));
            }
        }

        // the collection view sources data binds to this
        private ObservableCollection<WPChamp> m_Champs = new ObservableCollection<WPChamp>();
        public ObservableCollection<WPChamp> Champs
        {
            get { return m_Champs; }
        }

        #endregion

        #region methods

        // lets you know when the data has been returned
        public event EventHandler<LoadChampsCompleteEventArgs> LoadChampsComplete;
        public class LoadChampsCompleteEventArgs : EventArgs { public Exception Error { get; set; } }

        // call this to refresh data from service (starts async, non-blocking)
        public void LoadChamps(int? id = null)
        {
            // Don't reload the data if we already have it in memory
            if (IsDataLoaded)
                return;

            // setup async query
            var _Root = new Uri("http://champ.cloudapp.net/ChampDataService.svc");
            var _Context = new ChampEntities(_Root);
            var _Query = _Context.Champs as IQueryable<Champ>;
            if (id.HasValue) // allow to load only one
                _Query = _Context.Champs.Where(x => x.ID == id);
            var _List = new DataServiceCollection<Champ>(_Context);
            _List.LoadCompleted += (s, e) =>
            {
                ProgressBarVisibility = Visibility.Collapsed;
                if (e.Error != null && LoadChampsComplete != null)
                    LoadChampsComplete(this, new LoadChampsCompleteEventArgs { Error = e.Error });
                else
                    LoadCompleted(_List);
            };

            // start async query
            ProgressBarVisibility = Visibility.Visible;
            _List.LoadAsync(_Query);
        }

        // private method, handling compelted async service call 
        private void LoadCompleted(DataServiceCollection<Champ> list)
        {
            // handle load complete
            if (list.Continuation != null)
            {
                list.LoadNextPartialSetAsync();
                return;
            }

            // update the local list
            foreach (Champ _Champ in list)
            {
                var _Existing = Champs.Where(x => x.ID == _Champ.ID).FirstOrDefault();

                // not in list, so add to list
                if (_Existing == null)
                {
                    // create, add to the list
                    _Existing = new WPChamp(_Champ);
                    Champs.Add(_Existing);
                }

                // update in list
                else
                    _Existing.Update(_Champ);

                // bubble up DistanceChanged
                _Existing.DistanceChanged -= BubbleDistanceChanged;
                _Existing.DistanceChanged += BubbleDistanceChanged;
            }

            // remove deleted
            var _Remove = Champs.Where(x => !list.Select(y => y.ID).Contains(x.ID)).ToList();
            _Remove.ForEach(x => Champs.Remove(x));

            // raise completed
            if (LoadChampsComplete != null)
                LoadChampsComplete(this, new LoadChampsCompleteEventArgs());
            IsDataLoaded = true;
        }

        private void BubbleDistanceChanged(object sender, EventArgs e)
        {
            if (DistanceChanged != null)
                DistanceChanged(sender, e);
        }

        #endregion
    }
}
